package cn.rgb.orm.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

import javax.sql.DataSource;

import cn.rgb.dao.ConnectionPool;
import cn.rgb.orm.ResultGetter;
import cn.rgb.orm.SqlExecutor;
import cn.rgb.orm.config.SqlMapConfig;
import cn.rgb.orm.config.SqlMapping;

public class SqlExecutorImpl implements SqlExecutor {
	private DataSource ds;
	private SqlMapConfig sqlMapConfig;
	private ConnectionPool connPool;
	private StatementArgsMapper argsMapper;
	private ResultGetter resultGetter;
	
	
	public SqlExecutorImpl(SqlMapConfig sqlMapConfig) {
		this.sqlMapConfig = sqlMapConfig;
		this.connPool = new ConnectionPool(sqlMapConfig.getDsInfo());
		this.argsMapper= new StatementArgsMapper();
		this.resultGetter = new ResultGetterImpl();
	}
	
	@Override
	public Object insert(String sqlId) throws SQLException {
		return insert(sqlId, null);
	}

	@Override
	public Object insert(String sqlId, Object param) throws SQLException {
		String namespace = "";
		String operSqlId = sqlId;
		int dotPos = sqlId.indexOf('.');
		if(dotPos > 0) {
			namespace = sqlId.substring(0, dotPos);
			operSqlId = sqlId.substring(dotPos + 1);
		}
		SqlMapping sqlMapping = sqlMapConfig.getSqlMapping(namespace);
		
		Connection conn = getAndSaveConnection();

		PreparedStatement ps = argsMapper.setStatementArgs(operSqlId, conn, param, sqlMapping);
		ps.execute();
		return null;
	}

	@Override
	public Object delete(String sqlId) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object delete(String sqlId, Object params) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object update(String sqlId) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object update(String sqlId, Object params) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object queryForObject(String sqlId) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object queryForObject(String sqlId, Object params)
			throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List<Object> queryForList(String sqlId) throws SQLException {
		// TODO Auto-generated method stub
		return queryForList(sqlId, null);
	}

	@Override
	public List<Object> queryForList(String sqlId, Object param) throws SQLException {
		String namespace = "";
		String operSqlId = sqlId;
		int dotPos = sqlId.indexOf('.');
		if(dotPos > 0) {
			namespace = sqlId.substring(0, dotPos);
			operSqlId = sqlId.substring(dotPos + 1);
		}
		SqlMapping sqlMapping = sqlMapConfig.getSqlMapping(namespace);
		
		Connection conn = getAndSaveConnection();

		PreparedStatement ps = argsMapper.setStatementArgs(operSqlId, conn, param, sqlMapping);
		ResultSet rs = ps.executeQuery();
		return resultGetter.getListResult(rs, sqlMapConfig, sqlMapping, null);
	}

	@Override
	public Connection getConnection() throws SQLException {
		return null;
	}

	@Override
	public Connection getCurrentConnection() throws SQLException {
//		Thread.currentThread()
		return null;
	}

	public void close(Connection conn, Statement st, ResultSet rs) {
		if(rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if(st != null) {
			try {
				st.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if(conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public void startTransaction() throws SQLException {
		Connection conn = getAndSaveConnection();
		conn.setAutoCommit(false);
	}

	@Override
	public void commitTransaction() throws SQLException {
		Connection conn = ConnectionPool.getCurrentConnection();
		if(conn != null) {
			conn.commit();
		}
	}
	
	@Override
	public void rollbackTransaction() throws SQLException {
		Connection conn = ConnectionPool.getCurrentConnection();
		if(conn != null) {
			conn.rollback();
		}
	}
	
	private Connection getAndSaveConnection() {
		Connection conn = ConnectionPool.getCurrentConnection();
		if(conn == null) {
			conn = connPool.getConnection();
			ConnectionPool.saveConnection(conn);
		}
		return conn;
	}

	@Override
	public void setDataSource(DataSource ds) {
		this.ds = ds;
	}
}
